class Element(object):
    def accept(self, visitor):
        return getattr(visitor, "visit_%s" % (self.__class__.__name__,))(self)
    def __add__(self, other): 
        return Adder(self, other)
    def __sub__(self, other): 
        return Subtracter(self, other)
    def __mul__(self, other): 
        return Multiplier(self, other)
    def __div__(self, other): 
        return Divider(self, other)
    def __and__(self, other): 
        return Ander(self, other)
    def __or__(self, other): 
        return Orer(self, other)
    def __xor__(self, other): 
        return Xorer(self, other)
    def __neg__(self): 
        return Negator(self)
    def __pos__(self): 
        return Posator(self)
    def __inv__(self): 
        return Inverter(self)
    def __eq__(self, other):
        return Equator(self, other)
    def __ne__(self, other):
        return Inequator(self, other)
    def __gt__(self, other):
        return Greator(self, other)
    def __ge__(self, other):
        return GreatorEquator(self, other)
    def __lt__(self, other):
        return Lessor(self, other)
    def __le__(self, other):
        return LessorEquator(self, other)

class UnaryOperator(Element):
    def __init__(self, value):
        self.value = value
    def __repr__(self):
        return "%s(%r)" % (self.__class__.__name__, self.value)

class BinaryOperator(Element):
    def __init__(self, left, right):
        self.left = left
        self.right = right
    def __repr__(self):
        return "%s(%r, %r)" % (self.__class__.__name__, self.left, self.right)

class Const(UnaryOperator): pass
class Symbol(UnaryOperator): pass
class Negator(UnaryOperator): pass
class Posator(UnaryOperator): pass
class Inverter(UnaryOperator): pass
class Adder(BinaryOperator): pass
class Subtracter(BinaryOperator): pass
class Multiplier(BinaryOperator): pass
class Divider(BinaryOperator): pass
class Ander(BinaryOperator): pass
class Orer(BinaryOperator): pass
class Xorer(BinaryOperator): pass
class Equator(BinaryOperator): pass
class Inequator(BinaryOperator): pass
class Greator(BinaryOperator): pass
class GreatorEquator(BinaryOperator): pass
class Lessor(BinaryOperator): pass
class LessorEquator(BinaryOperator): pass

class EvaluateVisitor(object):
    def __init__(self, root, symboltable):
        self.symboltable = symboltable
        self.result = root.accept(self)
    def visit_Equator(self, obj):
        return obj.left.accept(self) == obj.right.accept(self)
    def visit_Inequator(self, obj):
        return obj.left.accept(self) != obj.right.accept(self)
    def visit_Greator(self, obj):
        return obj.left.accept(self) > obj.right.accept(self)
    def visit_Ander(self, obj):
        return obj.left.accept(self) and obj.right.accept(self)
    def visit_Orer(self, obj):
        return obj.left.accept(self) or obj.right.accept(self)
    def visit_Adder(self, obj):
        return obj.left.accept(self) + obj.right.accept(self)
    def visit_Subtracter(self, obj):
        return obj.left.accept(self) - obj.right.accept(self)
    def visit_Const(self, obj):
        return obj.value
    def visit_Symbol(self, obj):
        return self.symboltable[obj.value]

class SqlVisitor(object):
    def __init__(self, root):
        self.text = ["WHERE"]
        root.accept(self)
        self.sql = " ".join(self.text)
    def __str__(self):
        return self.sql
    def unary_visitor(self, textoperator, obj):
        self.text.append(textoperator)
        obj.value.accept(self)
    def binary_visitor(self, textoperator, obj):
        obj.left.accept(self)
        self.text.append(textoperator)
        obj.right.accept(self)
    def visit_Equator(self, obj):
        self.binary_visitor("=", obj)
    def visit_Greator(self, obj):
        self.binary_visitor(">", obj)
    def visit_Inequator(self, obj):
        self.binary_visitor("<>", obj)
    def visit_Ander(self, obj):
        self.binary_visitor("AND", obj)
    def visit_Ander(self, obj):
        self.binary_visitor("AND", obj)
    def visit_Orer(self, obj):
        self.binary_visitor("OR", obj)
    def visit_Inverter(self, obj):
        self.unary_visitor("NOT", obj)
    def visit_Const(self, obj):
        self.text.append(repr(obj.value))
    def visit_Symbol(self, obj):
        self.text.append(str(obj.value))


if __name__ == "__main__":
    x = (Symbol("age") > Const(17)) & (Symbol("firstname") == Const("blah"))
    
    print x
    # Ander(Greator(Symbol('age'), Const(17)), Equator(Symbol('firstname'), Const('blah')))
    
    print SqlVisitor(x)
    # WHERE age > 17 AND firstname = 'blah'
    
    print EvaluateVisitor(x, {"age" : 50, "firstname" : "blah"}).result
    # True
    
    print EvaluateVisitor(x, {"age" : 5, "firstname" : "blah"}).result
    # False































